import { Config, DateBuilder } from "@spacebar/util";
import { AbuseIpDbBlacklistResponse, AbuseIpDbCheckResponse } from "./AbuseIpDbSampleResponses";

export class AbuseIpDbClient {
	private static ipCheckCache: Map<
		string,
		{
			data: AbuseIpDbCheckResponse;
			expires: number;
		}
	> = new Map();

	private static blacklistCache: {
		data: AbuseIpDbBlacklistResponse;
		expires: number;
	} | null = null;

	static async checkIpAddress(ip: string): Promise<AbuseIpDbCheckResponse | null> {
		const { ipdataApiKey } = Config.get().security;
		if (!ipdataApiKey) return null;
		if (this.ipCheckCache.get(ip)?.expires ?? 0 > Date.now()) return this.ipCheckCache.get(ip)!.data;

		console.log(`[AbuseIPDB] Checking IP address ${ip}...`);
		const resp = (await (await fetch(`https://api.abuseipdb.com/api/v2/check?ipAddress=${ip}`)).json()) as Promise<AbuseIpDbCheckResponse>;
		this.ipCheckCache.set(ip, {
			data: await resp,
			expires: new DateBuilder().addHours(12).buildTimestamp(),
		});
		return await resp;
	}

	static async getBlacklist(): Promise<AbuseIpDbBlacklistResponse | null> {
		const { abuseIpDbApiKey, abuseipdbBlacklistRatelimit } = Config.get().security;
		if (!abuseIpDbApiKey) return null;
		if (this.blacklistCache?.expires ?? 0 > Date.now()) return this.blacklistCache!.data;

		console.log("[AbuseIPDB] Fetching blacklist...");
		const resp = (await (
			await fetch(`https://api.abuseipdb.com/api/v2/blacklist`, {
				headers: {
					Key: abuseIpDbApiKey,
					Accept: "application/json",
				},
			})
		).json()) as Promise<AbuseIpDbBlacklistResponse>;

		this.blacklistCache = {
			data: await resp,
			expires: new DateBuilder().addHours(Math.ceil(24 / abuseipdbBlacklistRatelimit)).buildTimestamp(),
		};

		return await resp;
	}

	static async isIpBlacklisted(ip: string): Promise<boolean> {
		const { abuseipdbConfidenceScoreTreshold } = Config.get().security;
		const blacklist = await this.getBlacklist();
		if (!blacklist) return false;

		const entry = blacklist.data.find((x) => x.ipAddress === ip);
		if (!entry) return false;

		return entry.abuseConfidenceScore >= abuseipdbConfidenceScoreTreshold;
	}
}
